package cn.tedu.selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class Server {

    public static void main(String[] args) throws IOException {

        // 开启服务器端的通道
        ServerSocketChannel ssc = ServerSocketChannel.open();
        // 绑定端口
        ssc.bind(new InetSocketAddress(8090));
        // 设置为非阻塞
        ssc.configureBlocking(false);

        // 开启选择器
        Selector selector = Selector.open();
        // 将通道注册到选择器上
        ssc.register(selector, SelectionKey.OP_ACCEPT);

        // 实际过程中，服务器开启之后应该是不关闭的
        while (true) {

            // 随着服务器运行的时间的延长，那么服务器接收到的客户端请求就会越来越多
            // 需要筛选出来其中的有用的请求 - 能触发服务器的对应的操作
            selector.select();
            // 这些请求能够触发服务器的accept/read/write操作
            // 并不是每一次筛选之后，剩下的请求都能够触发的所有操作
            // 需要确定到底能够触发服务器的哪类操作
            Set<SelectionKey> set = selector.selectedKeys();
            // 遍历这个集合，然后根据不同的操作类型来分别处理
            Iterator<SelectionKey> it = set.iterator();
            while (it.hasNext()) {
                SelectionKey key = it.next();
                if (key.isAcceptable()) {
                    // 从操作类型中获取到要处理的Channel
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    // 接收连接
                    SocketChannel sc = channel.accept();
                    sc.configureBlocking(false);
                    // 注册可读事件
                    // sc.register(selector, SelectionKey.OP_READ);
                    // 注册可写事件
                    // 在注册时候，后一次注册的事件会将之前注册的事件给覆盖掉
                    // sc.register(selector, SelectionKey.OP_WRITE);
                    // sc.register(selector, SelectionKey.OP_READ + SelectionKey.OP_WRITE);
                    // sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                    sc.register(selector, SelectionKey.OP_READ ^ SelectionKey.OP_WRITE);
                }
                if (key.isReadable()) {
                    // 从事件类型中获取到通道
                    SocketChannel sc = (SocketChannel) key.channel();
                    // 读取数据
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    sc.read(buffer);
                    System.out.println(new String(buffer.array(), 0, buffer.position()));
                    // 注销读操作
                    // key.interestOps() 获取这个通道上的所有的操作
                    // sc.register(selector, key.interestOps() ^ SelectionKey.OP_READ);
                    sc.register(selector, key.interestOps() - SelectionKey.OP_READ);
                }
                if (key.isWritable()) {
                    // 从事件类型汇总获取到通道
                    SocketChannel sc = (SocketChannel) key.channel();
                    // 写出数据
                    sc.write(ByteBuffer.wrap("hello client".getBytes()));
                    // 注销写操作
                    sc.register(selector, key.interestOps() ^ SelectionKey.OP_WRITE);
                }
                // 当这一个通道上的操作被处理完之后，这个通道应该被移除
                it.remove();
            }

        }

    }

}
